/*
	service 是各service通用的
*/
package service

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"sync"
	"web-service-demo/registry"
)

// Start 帮助各service启动HTTP服务，这里是所有service相同的启动过程
func Start(ctx context.Context, host, port string, reg registry.Registration, registerHandlersFunc func()) (context.Context, error) {
	//设置 service 的 HTTP handler
	registerHandlersFunc()
	//设置通用HTTP handler（心跳检测 和 更新依赖服务）
	registerCommonHandlers(reg)
	//启动 service 的 HTTP服务器
	ctx = startService(ctx, reg.ServiceName, host, port)
	//向 registry 注册服务
	err := registerService(reg)
	if err != nil {
		return ctx, err
	}

	return ctx, nil
}

//设置通用HTTP handler（心跳检测 和 更新依赖服务）
func registerCommonHandlers(reg registry.Registration) {
	//处理心跳检测
	heartbeatURL, err := url.Parse(reg.HeartbeatURL)
	if err != nil {
		log.Println(err)
	}
	http.HandleFunc(heartbeatURL.Path, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	//处理依赖服务的更新
	serviceUpdateURL, err := url.Parse(reg.ServiceUpdateURL)
	if err != nil {
		log.Println(err)
	}
	http.HandleFunc(serviceUpdateURL.Path, func(w http.ResponseWriter, r *http.Request) {
		//确保是POST方法
		if r.Method != http.MethodPost {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
		//解析Body
		dec := json.NewDecoder(r.Body)
		var p registry.Patch
		err := dec.Decode(&p)
		if err != nil {
			log.Println(err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		//更新数据
		fmt.Printf("Updated received %v\n", p)
		prov.update(p)
	})
}

// 启动 service 的 HTTP服务器
func startService(ctx context.Context, serviceName string, host string, port string) context.Context {
	ctx, cancel := context.WithCancel(ctx)

	var srv http.Server
	srv.Addr = host + ":" + port

	//后台运行服务
	go func() {
		log.Println(srv.ListenAndServe())
		log.Println("[listenAndServe,cancel]")
		err := shutdownService(fmt.Sprintf("http://%s:%s", host, port))
		if err != nil {
			log.Println(err)
		}
		cancel() //通知主goroutine结束
	}()

	//后台接收关闭操作
	go func() {
		fmt.Printf("%v started. Press any key to stop.\n", serviceName)
		var s string
		fmt.Scanln(&s)
		log.Println("[press key,cancel]")
		//err := shutdownService(fmt.Sprintf("http://%s:%s", host, port))
		//if err != nil {
		//	log.Println(err)
		//}
		srv.Shutdown(ctx)
		//cancel() //通知主goroutine结束
	}()

	return ctx
}

//向 registry 注册服务
func registerService(reg registry.Registration) error {
	//准备数据
	buf := new(bytes.Buffer)
	enc := json.NewEncoder(buf)
	err := enc.Encode(reg)
	if err != nil {
		return err
	}

	//发送注册服务
	res, err := http.Post(registry.ServicesURL, "application/json", buf)
	if err != nil {
		return err
	}

	//处理注册结果
	if res.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to register service. code %v", res.StatusCode)
	}

	return nil
}

//向 registry 取消服务
func shutdownService(url string) error {
	//准备Request，因为没有http.Delete()方法
	req, err := http.NewRequest(http.MethodDelete, registry.ServicesURL, bytes.NewBuffer([]byte(url)))
	if err != nil {
		return err
	}
	req.Header.Add("Content-Type", "text/plain")

	//发送取消服务
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}

	//处理返回结果
	if res.StatusCode != http.StatusOK {
		return fmt.Errorf("Failed to deregister service. Registry service respond with code %v", res.StatusCode)
	}

	return nil
}

//全局变量
var prov = providers{
	services: make(map[string][]string),
	mutex:    new(sync.RWMutex),
}

// GetProvider 获取依赖服务的URL
func GetProvider(name string) (string, error) {
	return prov.get(name)
}
